---
title: Sync a keyword batch with OnBase
summary: Constructs the OnBase SOAP client, evaluates each record, and marks records processed once their update set completes.
status: draft
owner: Documents
last_reviewed: 2026-09-17
operation_id: OP-003
trigger: Step 7 of OP-001, via OnBaseKeywordSyncRunner.SyncDataWithOnBase
---

# OP-003: Sync a keyword batch with OnBase

For the ordered unprocessed record array, this operation constructs one `OnBaseKeywordSyncClient` per batch, reads the document-counting flag, evaluates and sends each record's updates, then marks every record processed — even records that were skipped.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-003 |
| **Trigger** | Step 7 of [OP-001](run-the-onbase-keyword-sync.md), via `OnBaseKeywordSyncRunner.SyncDataWithOnBase` |
| **Lifecycle stage** | Execute |
| **Owning component** | `KeywordUpdater.Update(ImageKeywordSync[] keywordBatch, bool runAsync)` |
| **Inputs** | The ordered unprocessed record array, the async flag |
| **Outputs** | OnBase keyword updates sent; every record marked processed in the Imaging API |
| **Failure exit code** | `5` — propagates from `OnBaseKeywordSyncRunner.Execute`'s catch block |

## Steps

1. Construct `OnBaseKeywordSyncClient` (one per batch): read `OnBaseKeywordUpdateServiceUrl` and create `HylandOutBoundContractClient("BasicHttpBinding_HylandOutBoundContract", url)`
   - On failure: a missing setting or bad endpoint throws an exception → exit code `5`
2. Read `OnBaseKeywordSync.getdocumentcount` and `Convert.ToBoolean` it ([BR-OBKS-003](../business-rules.md#br-obks-003-unprocessed-records-processed-in-ascending-id-order))
   - On failure: an unconvertible value throws `FormatException` → exit code `5`
3. For each record, evaluate [OP-004](decide-whether-a-record-is-sent-to-onbase.md) and log the record header block ([BR-OBKS-004](../business-rules.md#br-obks-004-document-count-gates-whether-a-record-is-sent), [BR-OBKS-005](../business-rules.md#br-obks-005-equal-prior-and-new-values-are-not-sent), [BR-OBKS-006](../business-rules.md#br-obks-006-trigger-type-and-query-keyword-derived-by-precedence), [BR-OBKS-009](../business-rules.md#br-obks-009-flag-keyword-translation))
4. When `PerformUpdate` is true, for each `KeywordUpdate` in the record: skip with `"No document to update"` when document counting is on and `DocumentCount == 0`; otherwise delegate to [OP-005](send-one-keyword-update-to-onbase.md) ([BR-OBKS-007](../business-rules.md#br-obks-007-empty-new-value-applied-as-keyword-deletion))
5. Raise `OnBaseKeywordUpdateSetComplete` for the record — **unconditionally**, including when no update was sent ([BR-OBKS-010](../business-rules.md#br-obks-010-every-record-marked-processed-after-its-update-set-completes))
   - On failure: a handler failure aborts the batch
6. Handler `Updater_OnBaseKeywordUpdateSetComplete` calls `POST ImageKeywordSyncs/MarkProcessed?id={Keyword.Id}` ([BR-OBKS-010](../business-rules.md#br-obks-010-every-record-marked-processed-after-its-update-set-completes))
   - On failure: propagates → exit code `5`; `MarkAsProcessedException` exists but is never constructed or thrown
7. Log a blank line between records

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
    A["Construct OnBaseKeywordSyncClient"] --> B["Read getdocumentcount flag"]
    B --> C["For each record:<br>OP-004 decide send/skip"]
    C --> D{"Send decision?"}
    D -->|Send| E["For each KeywordUpdate:<br>OP-005 send to OnBase"]
    D -->|Skip| F["Log skip reason"]
    E --> G["Raise OnBaseKeywordUpdateSetComplete<br>unconditionally"]
    F --> G
    G --> H["Mark record processed<br>in Imaging API"]
    H --> I{"More records?"}
    I -->|Yes| C
    I -->|No| J["Batch complete"]
    A -.->|Missing setting| ERR["Exit code 5"]
    B -.->|FormatException| ERR
    G -.->|Handler failure| ERR
    H -.->|Exception| ERR
```

## Logging

| Log id | Written content |
| --- | --- |
| Not application-assigned (fans out to all registered `file0`–`file4` writers) | Per-record block: `image_keyword_sync` ID, trigger type, doc type group, keyword, prior value, new value, and either the counts to update or the reason nothing will be sent; a blank line between records |

## Error handling
- A failure constructing `OnBaseKeywordSyncClient`, converting `getdocumentcount`, or in the `OnBaseKeywordUpdateSetComplete` handler propagates to `OnBaseKeywordSyncRunner.Execute`'s catch block, which logs and rethrows → exit code `5`.
- There is no per-record error isolation: one failed record aborts the remaining batch*.

## Related documentation
- [Run lifecycle](../run-lifecycle.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Operational runbook](../operational-runbook.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

## Sources
- `OnBaseKeywordSync/Services/KeywordUpdater.cs`
- `OnBaseKeywordSync/Services/OnBaseKeywordSyncClient.cs`
- `OnBaseKeywordSync/OnBaseKeywordSyncRunner.cs`
- `OnBaseKeywordSync/Services/ImagingApiClient.cs`
- `OnBaseKeywordSync/Exceptions/MarkAsProcessedException.cs`
